/**
  ******************************************************************************
  * @file    sym32l010_hal_uart.c
  * @author
  * @version 1.0.3
  * @date    2024-05-28
  * @brief   UART HAL module driver.
  *
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2024 SIYIMicro.
  * All rights reserved.</center></h2>
  *
  *
  ******************************************************************************
  */


/******************************************************************************/
/* Include files                                                              */
/******************************************************************************/
#include "sym32l010_hal_uart.h"
#include "sym32l010_hal_systick.h"

/*******************************************************************************
  * @brief  UART 初始化，采用小数波特率方式
  * @param  hUart      : 待通信的UART句柄
  * @retval HAL status : HAL_OK    代表UART初始化成功
                         HAL_ERROR 代表UART初始化失败
  * @note   需通过APBENx寄存器使能UARTx的时钟后，才可调用该函数
  */
HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *hUart)
{
    if (hUart == NULL)
    {
        return HAL_ERROR;
    }

    uint32_t BRR = (hUart->Init.PclkFreq + (hUart->Init.BaudRate>>1UL)) / hUart->Init.BaudRate;

    hUart->Instance->CR1  = (uint32_t)hUart->Init.WorkMode   | (uint32_t)hUart->Init.SingleWireEn |
                            (uint32_t)hUart->Init.RxdStart | (uint32_t)hUart->Init.FirstBit |
                            (uint32_t)hUart->Init.StopBits   | (uint32_t)hUart->Init.ParityMode;

    hUart->Instance->CR2  = (uint32_t)hUart->Init.Polarity    | (uint32_t)hUart->Init.HwControl |
                            (uint32_t)hUart->Init.SlaveAddrEn | (uint32_t)hUart->Init.SwapEn;

    hUart->Instance->BRRI = BRR >> 4UL;
    hUart->Instance->BRRF = BRR;
    hUart->Instance->IER  = 0x00;

    hUart->Instance->ADDR = hUart->Init.SlaveAddr;
    hUart->Instance->MASK = hUart->Init.SlaveAddrMask;

    return HAL_OK;
}


/*******************************************************************************
  * @brief  UART 低功耗初始化，采用专用波特率生成方式。用于32768-> 9600 / 4800 / 2400。
  * @param  hUart      : 待通信的UART句柄
  * @retval HAL status : HAL_OK    代表UART初始化成功
                         HAL_ERROR 代表UART初始化失败
  * @note   需通过APBENx寄存器使能UARTx的时钟后，才可调用该函数
  */
HAL_StatusTypeDef HAL_UART_LpInit(UART_HandleTypeDef *hUart)
{
    if (hUart == NULL)
    {
        return HAL_ERROR;
    }

    hUart->Instance->CR1  = (0x3UL << UARTx_CR1_OVER_Pos)       | (uint32_t)hUart->Init.RxdStart    |
                            (uint32_t)hUart->Init.WorkMode      | (uint32_t)hUart->Init.StopBits    |
                            (uint32_t)hUart->Init.ParityMode    | (uint32_t)hUart->Init.ClockSource |
                            (uint32_t)hUart->Init.SingleWireEn  | (uint32_t)hUart->Init.FirstBit;

    hUart->Instance->CR2  = (uint32_t)hUart->Init.Polarity    | (uint32_t)hUart->Init.HwControl  |
                            (uint32_t)hUart->Init.SlaveAddrEn | (uint32_t)hUart->Init.SwapEn;

    hUart->Instance->BRRI = (32768 * 256 + (hUart->Init.BaudRate>>1UL)) / hUart->Init.BaudRate;

    hUart->Instance->ADDR = hUart->Init.SlaveAddr;
    hUart->Instance->MASK = hUart->Init.SlaveAddrMask;

    return HAL_OK;
}


/*******************************************************************************
  * @brief  UART 反初始化
  * @param  hUart      : 待通信的UART句柄
  * @retval HAL status : HAL_OK    代表UART反初始化成功
                         HAL_ERROR 代表UART反初始化失败
  */
HAL_StatusTypeDef HAL_UART_DeInit(UART_HandleTypeDef *hUart)
{
    HAL_StatusTypeDef status = HAL_OK;

    if (hUart == NULL)
    {
        return HAL_ERROR;
    }

    switch ((uint32_t)hUart->Instance)
    {
        case (uint32_t)SYM_UART1:
            REGBITS_CLR(SYM_SYSCTRL->APBRST1, SYSCTRL_APBRST1_UART1_Msk);
            REGBITS_SET(SYM_SYSCTRL->APBRST1, SYSCTRL_APBRST1_UART1_Msk);
            break;
        case (uint32_t)SYM_UART2:
            REGBITS_CLR(SYM_SYSCTRL->APBRST1, SYSCTRL_APBRST1_UART2_Msk);
            REGBITS_SET(SYM_SYSCTRL->APBRST1, SYSCTRL_APBRST1_UART2_Msk);
            break;
        default:
            status = HAL_ERROR;
            break;
    }

    return status;
}


/*******************************************************************************
  * @brief  UART RXD使能
  * @param  UARTx: UART名称
  *                @arg SYM_UART1
  *                @arg SYM_UART2
  * @retval None
  */
void HAL_UART_RXD_Enable(UART_TypeDef *UARTx)
{
    UARTx->ICR = 0x0;
    REGBITS_SET(UARTx->CR1, UARTx_CR1_RXEN_Msk);
}


/*******************************************************************************
  * @brief  UART RXD禁止
  * @param  UARTx: UART名称
  *                @arg SYM_UART1
  *                @arg SYM_UART2
  * @retval None
  */
void HAL_UART_RXD_Disable(UART_TypeDef *UARTx)
{
    REGBITS_CLR(UARTx->CR1, UARTx_CR1_RXEN_Msk);
}


/*******************************************************************************
  * @brief  UART TXD使能
  * @param  UARTx: UART名称
  *                @arg SYM_UART1
  *                @arg SYM_UART2
  * @retval None
  *
  */
void HAL_UART_TXD_Enable(UART_TypeDef *UARTx)
{
    UARTx->ICR = ~UART_IT_FLAG_TC;
    REGBITS_SET(UARTx->CR1, UARTx_CR1_TXEN_Msk);
}


/*******************************************************************************
  * @brief  UART TXD禁止
  * @param  UARTx: UART名称
  *                @arg SYM_UART1
  *                @arg SYM_UART2
  * @retval None
  */
void HAL_UART_TXD_Disable(UART_TypeDef *UARTx)
{
    REGBITS_CLR(UARTx->CR1, UARTx_CR1_TXEN_Msk);
}


/*******************************************************************************
  * @brief  向串口发送一个字节
  * @param  UARTx: UART名称
  *                @arg SYM_UART1
  *                @arg SYM_UART2
  * @param  ch   : 待发送8bit数据
  * @retval None
  */
void HAL_UART_SendByte(UART_TypeDef *UARTx, uint8_t ch)
{
    UARTx->ICR = ~UART_IT_FLAG_TC;
    UARTx->TDR = ch;
    while (REGBITS_GET(UARTx->ISR, UART_IT_FLAG_TC) == 0) { ; }
}


/*******************************************************************************
  * @brief  向串口发送一帧9bit数据
  * @param  UARTx   : UART名称
  *                   @arg SYM_UART1
  *                   @arg SYM_UART2
  * @param  halfword: uint16_t类型，待发送的9bit数据
  * @retval None
  */
void HAL_UART_SendHalfWord(UART_TypeDef *UARTx, uint16_t halfword)
{
    UARTx->ICR = ~UART_IT_FLAG_TC;
    UARTx->TDR = halfword;
    while (REGBITS_GET(UARTx->ISR, UART_IT_FLAG_TC) == 0) { ; }
}


/*******************************************************************************
  * @brief  从串口接收一个字节
  * @param  UARTx: UART名称
  *                @arg SYM_UART1
  *                @arg SYM_UART2
  * @retval 返回接收到的字节，不验证接收是否出错
  */
uint8_t HAL_UART_RecvByte(UART_TypeDef *UARTx)
{
    while (REGBITS_GET(UARTx->ISR, UART_IT_FLAG_RC) == 0) { ; }
    UARTx->ICR = ~UART_IT_FLAG_RC;
    return UARTx->RDR;
}


/*******************************************************************************
  * @brief  从串口接收一帧9bit数据
  * @param  UARTx: UART名称
  *                @arg SYM_UART1
  *                @arg SYM_UART2
  * @retval 以uint16_t类型返回接收到的9bit数据，不验证接收是否出错
  */
uint16_t HAL_UART_RecvHalfWord(UART_TypeDef *UARTx)
{
    while (REGBITS_GET(UARTx->ISR, UART_IT_FLAG_RC) == 0) { ; }
    UARTx->ICR = ~UART_IT_FLAG_RC;
    return UARTx->RDR;
}


/*******************************************************************************
  * @brief  通过查询方式发送UART数据
  * @param  hUart      : 待通信的UART句柄
  * @param  pData      : 待发送的数据的存放指针
  * @param  Size       : 待发送的数据的帧数
  * @param  TimeOut    : 等待接收数据的超时时间，以ms为单位。
  *                      0代表一直等待，没有超时功能
  * @retval HAL status : HAL_OK      代表成功完成接收
  *                      HAL_TIMEOUT 代表接收超时
  *                      HAL_ERROR   代表接收出错
  */
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *hUart, uint8_t *pData, uint32_t Size, uint32_t TimeOut)
{
    if ((hUart == NULL) || (pData == NULL) || (Size == 0))
    {
        return HAL_ERROR;
    }

    hUart->pTxBuffPtr  = pData;
    hUart->TxXferSize  = Size;
    hUart->TxXferCount = Size;
    hUart->RxState     = HAL_BUSY;

    uint32_t TickStart = HAL_GetTick();

    if (hUart->Init.WorkMode == UART_WORKMODE_ASYN)
    {
        HAL_UART_TXD_Enable(hUart->Instance);                         // 使能UART的TXD功能
    }
    else
    {
        HAL_UART_RXD_Disable(hUart->Instance);
        HAL_UART_TXD_Enable(hUart->Instance);
    }

    while (hUart->TxXferCount > 0U)
    {
        if (HAL_UART_GET_FLAG(hUart, UART_IT_FLAG_TXE))
        {
            if (hUart->DataWidth < UART_DATAWIDTH_9BIT)
            {
                hUart->Instance->TDR = *(hUart->pTxBuffPtr);
                hUart->pTxBuffPtr++;
            }
            else
            {
                hUart->Instance->TDR = *((uint16_t *)hUart->pTxBuffPtr);
                hUart->pTxBuffPtr += 2;
            }
            hUart->TxXferCount--;
        }
        if (TimeOut && ((HAL_GetTick() - TickStart) > TimeOut))       // 超时出错
        {
            hUart->RxState = HAL_TIMEOUT;
            return HAL_TIMEOUT;
        }
    }

    while (HAL_UART_GET_FLAG(hUart, UART_IT_FLAG_TXBUSY))
    {
        if (TimeOut && ((HAL_GetTick() - TickStart) > TimeOut))       // 超时出错
        {
            hUart->RxState = HAL_TIMEOUT;
            return HAL_TIMEOUT;
        }
    }

    hUart->RxState = HAL_OK;
    return HAL_OK;
}


/*******************************************************************************
  * @brief  通过查询方式接收UART数据，同步模式专用
  * @param  hUart      : 待通信的UART句柄
  * @param  pData      : 待接收的数据的存放指针
  * @param  Size       : 待接收的数据的帧数
  * @param  TimeOut    : 等待接收数据的超时时间，以ms为单位。
  *                      0代表一直等待，没有超时功能
  * @retval HAL status : HAL_OK      代表成功完成接收
  *                      HAL_TIMEOUT 代表接收超时
  *                      HAL_ERROR   代表接收出错
  * @note   需要使能SYSTICK
  */
HAL_StatusTypeDef HAL_UART_Receive_Sync(UART_HandleTypeDef *hUart, uint8_t *pData, uint32_t Size, uint32_t TimeOut)
{
    if ((hUart == NULL) || (pData == NULL) || (Size == 0))
    {
        return HAL_ERROR;
    }

    HAL_UART_TXD_Disable(hUart->Instance);
    HAL_UART_RXD_Enable(hUart->Instance);                             // 使能UART的RXD功能

    hUart->pRxBuffPtr  = pData;
    hUart->RxXferSize  = Size;
    hUart->RxXferCount = Size;
    hUart->RxState     = HAL_BUSY;

    uint32_t TickStart = HAL_GetTick();

    while (1)
    {
        if (hUart->Instance->ISR & UART_IT_FLAG_RC)                   // 接收一个字节完成
        {
            *hUart->pRxBuffPtr = hUart->Instance->RDR;
            hUart->pRxBuffPtr++;
            hUart->RxXferCount--;

            if (hUart->RxXferCount > 0U)
            {
                HAL_UART_CLR_FLAG(hUart, UART_IT_FLAG_RC);
            }
            else
            {
                hUart->RxState = HAL_OK;
                break;
            }
        }
        if (TimeOut && (HAL_GetTick() - TickStart > TimeOut))         // 接收超时
        {
            hUart->RxState = HAL_TIMEOUT;
            break;
        }
    }
    HAL_UART_RXD_Disable(hUart->Instance);                            // 禁止UART的RXD功能
    HAL_UART_CLR_FLAG(hUart, UART_IT_FLAG_RC);

    return hUart->RxState;
}


/*******************************************************************************
  * @brief  通过查询方式接收UART数据，异步模式专用
  * @param  hUart      : 待通信的UART句柄
  * @param  pData      : 待接收的数据的存放指针
  * @param  Size       : 待接收的数据的帧数
  * @param  TimeOut    : 等待接收数据的超时时间，以ms为单位。
  *                      0代表一直等待，没有超时功能
  * @retval HAL status : HAL_OK      代表成功完成接收
  *                      HAL_TIMEOUT 代表接收超时
  *                      HAL_ERROR   代表接收出错
  * @note   需要使能SYSTICK
  */
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *hUart, uint8_t *pData, uint32_t Size, uint32_t TimeOut)
{
    if ((hUart == NULL) || (pData == NULL) || (Size == 0))
    {
        return HAL_ERROR;
    }

    hUart->pRxBuffPtr  = pData;
    hUart->RxXferSize  = Size;
    hUart->RxXferCount = Size;
    hUart->RxState     = HAL_BUSY;

    uint32_t TickStart = HAL_GetTick();

    HAL_UART_RXD_Enable(hUart->Instance);

    // 不定长串口功能初始化
    if (hUart->RxDoneFun == UART_RXDONE_EOP)
    {
        hUart->Instance->RXMATCH = hUart->RxEopChar;
        hUart->Instance->CR2_f.RXMATCHEN = 1;
    }
    else
    {
        hUart->Instance->CR2_f.RXMATCHEN = 0;
    }
    while (hUart->RxXferCount > 0U)
    {
        uint32_t IsrFlags = hUart->Instance->ISR;
        if (IsrFlags & (UART_IT_FLAG_PE | UART_IT_FLAG_FE | UART_IT_FLAG_NE)) // 接收到校验错误或帧结构错误
        {
            hUart->RxState = HAL_ERROR;
            return HAL_ERROR;
        }
        if (IsrFlags & UART_IT_FLAG_RC)                               // 接收一个字节完成
        {
            uint16_t tmp16 = hUart->Instance->RDR;
            HAL_UART_CLR_FLAG(hUart, UART_IT_FLAG_RC);
            if (hUart->DataWidth < UART_DATAWIDTH_9BIT)
            {
                *hUart->pRxBuffPtr = tmp16;
                hUart->pRxBuffPtr++;
            }
            else
            {
                *((uint16_t *)hUart->pRxBuffPtr) = tmp16;
                hUart->pRxBuffPtr += 2;
            }
            hUart->RxXferCount--;
        }

        if ((uint32_t)hUart->RxDoneFun & IsrFlags)                    // 处理指定字符结尾或空闲结尾的情况
        {
            HAL_UART_CLR_FLAG(hUart, (uint32_t)hUart->RxDoneFun);
            hUart->RxState = HAL_OK;
            return HAL_OK;
        }

        if (TimeOut && (HAL_GetTick() - TickStart > TimeOut))         // 接收超时
        {
            hUart->RxState = HAL_TIMEOUT;
            return HAL_TIMEOUT;
        }
    }

    if ((uint32_t)hUart->RxDoneFun)
    {
        return HAL_ERROR;
    }
    else
    {
        return HAL_OK;
    }
}


/*******************************************************************************
  * @brief  在中断服务程序中发送UART数据
  * @param  hUart: 待通信的UART句柄
  * @retval None
  * @note   需要在UARTx对应的TXE中断服务程序中调用本函数或将下方代码复制到中断服务程序
  */
static void HAL_UART_TxISR(UART_HandleTypeDef *hUart)
{
    if (hUart->DataWidth == UART_DATAWIDTH_8BIT)
    {
        hUart->Instance->TDR = *hUart->pTxBuffPtr;
        hUart->pTxBuffPtr++;
    }
    else
    {
        hUart->Instance->TDR = *((uint16_t *)hUart->pTxBuffPtr);
        hUart->pTxBuffPtr += 2;
    }
    hUart->TxXferCount--;
}


/*******************************************************************************
  * @brief  通过中断方式发送UART数据
  * @param  hUart      : 待通信的UART句柄
  * @param  pData      : 待发送的数据的存放指针
  * @param  Size       : 待发送的数据的帧数
  * @retval HAL status : HAL_OK    表示启动中断发送数据成功
  *                      HAL_ERROR 表示启动中断发送数据失败
  * @note   需要在UARTx对应的TXE中断服务程序中调用 HAL_UART_TxISR 函数
  *         在调用前，需使能NVIC
  */
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *hUart, uint8_t *pData, uint32_t Size)
{
    if ((hUart == NULL) || (pData == NULL) || (Size == 0))
    {
        return HAL_ERROR;
    }

    hUart->pTxBuffPtr  = pData;
    hUart->TxXferSize  = Size;
    hUart->TxXferCount = Size;
    hUart->TxState     = HAL_BUSY;

    hUart->TxISR = HAL_UART_TxISR;

    if (hUart->Init.WorkMode == UART_WORKMODE_ASYN)
    {
        HAL_UART_TXD_Enable(hUart->Instance);
    }
    else
    {
        if (hUart->RxState == HAL_BUSY)                               // 同步模式仅支持半双工
        {
            return HAL_ERROR;
        }
        hUart->DataWidth = UART_DATAWIDTH_8BIT;                       // 同步模式仅支持8bit数据位宽
        HAL_UART_RXD_Disable(hUart->Instance);
        HAL_UART_TXD_Enable(hUart->Instance);
    }
    HAL_UART_ENABLE_IT(hUart, UART_IT_SOURCE_TXE);

    return HAL_OK;
}


/*******************************************************************************
  * @brief  查询待通过中断发送的数据是否发送完成
  * @param  hUart      : 待通信的UART句柄
  * @retval HAL status : HAL_OK   代表成功完成发送
  *                      HAL_BUSY 代表正在发送中
  */
HAL_StatusTypeDef HAL_UART_Transmit_IT_IsComplete(UART_HandleTypeDef *hUart)
{
    if (hUart == NULL)
    {
        return HAL_ERROR;
    }
    if ((hUart->TxXferCount > 0U) || HAL_UART_GET_FLAG(hUart, UART_IT_FLAG_TXBUSY))
    {
        return HAL_BUSY;
    }
    else
    {
        return HAL_OK;
    }
}


/*******************************************************************************
  * @brief  在中断服务程序中接收UART数据
  * @param  hUart: 待通信的UART句柄
  * @retval None
  * @note   需要在UARTx对应的RC中断服务程序中调用本函数或将下方代码复制到中断服务程序
  */
static void UART_RxISR(UART_HandleTypeDef *hUart)
{
    if (hUart->DataWidth == UART_DATAWIDTH_8BIT)
    {
        *(hUart->pRxBuffPtr) = hUart->Instance->RDR;
        hUart->pRxBuffPtr++;
    }
    else
    {
        *((uint16_t *)hUart->pRxBuffPtr) = hUart->Instance->RDR;
        hUart->pRxBuffPtr += 2;
    }
    hUart->RxXferCount--;
    if (hUart->RxXferCount > 0U)
    {
        HAL_UART_CLR_FLAG(hUart, UART_IT_FLAG_RC);                    // 清除RC标志，在同步模式下的最后一帧数据无需清除
    }
}


/*******************************************************************************
  * @brief  UART结束传输函数，用于不定长数据传输
  * @param  hUart: 待通信的UART句柄
  * @retval None
  * @note   需要在UARTx对应的RC中断服务程序中调用本函数或将下方代码复制到中断服务程序
  */
static void UART_RxDoneFunc_FixLen(UART_HandleTypeDef *hUart)
{
    if (hUart->RxXferCount == 0U)                                     // 接收BUFF满
    {
        HAL_UART_DISABLE_IT(hUart, UART_IT_SOURCE_RC);
        hUart->RxState = HAL_OK;
    }
}

static void UART_RxDoneFunc_RxMatch(UART_HandleTypeDef *hUart)
{
    if (hUart->Flags & UART_IT_FLAG_RXMATCH)                          // 匹配到数据
    {
        hUart->Instance->CR2_f.RXMATCHEN = 0;
        hUart->RxState = HAL_OK;
    }
    else
    {
        if (hUart->RxXferCount == 0U)                                 // 接收BUFF满
        {
            hUart->Instance->CR2_f.RXMATCHEN = 0;
            hUart->RxState = HAL_ERROR;
        }
    }
    if (hUart->RxState != HAL_BUSY)
    {
        HAL_UART_DISABLE_IT(hUart, UART_IT_SOURCE_RC);
        HAL_UART_DISABLE_IT(hUart, UART_IT_FLAG_RXMATCH);
    }
}

static void UART_RxDoneFunc_RxIdle(UART_HandleTypeDef *hUart)
{
    if (hUart->Flags & UART_IT_FLAG_RXIDLE)                           // 收到空闲帧
    {
        hUart->RxState = HAL_OK;
    }
    else 
    {
        if (hUart->RxXferCount == 0U)
        {
            hUart->RxState = HAL_ERROR;
        }
    }
    if (hUart->RxState != HAL_BUSY)
    {
        HAL_UART_DISABLE_IT(hUart, UART_IT_SOURCE_RC);
        HAL_UART_DISABLE_IT(hUart, UART_IT_SOURCE_RXIDLE);
    }
}


/*******************************************************************************
  * @brief  通过中断方式接收UART数据
  * @param  hUart      : 待通信的UART句柄
  * @param  pData      : 待接收的数据的存放指针
  * @param  Size       : 待接收的数据的帧数
  * @retval HAL status : HAL_OK    表示启动中断接收数据成功
  *                      HAL_ERROR 表示启动中断接收数据失败
  * @note   需要在UARTx对应的RC中断服务程序中调用 HAL_UART_RxISR 函数
  *         在调用前，需使能NVIC
  */
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *hUart, uint8_t *pData, uint32_t Size)
{
    if ((hUart == NULL) || (pData == NULL) || (Size == 0))
    {
        return HAL_ERROR;
    }
   
    hUart->pRxBuffPtr  = pData;
    hUart->RxXferSize  = Size;
    hUart->RxXferCount = Size;
    hUart->RxState     = HAL_BUSY;
    
    HAL_UART_CLR_FLAG(hUart, UART_IT_FLAG_ALL);

    hUart->RxISR = UART_RxISR;
    
    if (hUart->Init.WorkMode == UART_WORKMODE_ASYN)                   // 异步模式
    {
        HAL_UART_RXD_Enable(hUart->Instance);                         // 使能UART的RXD功能
    }
    else                                                              // 同步模式
    {
        if (hUart->TxState == HAL_BUSY)                               // 同步模式仅支持半双工
        {
            return HAL_ERROR;
        }
        hUart->RxDoneFun = UART_RXDONE_FIXLEN;                        // 同步模式仅支持定长传输
        hUart->DataWidth = UART_DATAWIDTH_8BIT;                       // 同步模式仅支持8bit数据位宽
        HAL_UART_TXD_Disable(hUart->Instance);                        // 关闭UART的TXD功能
        HAL_UART_RXD_Enable(hUart->Instance);                         // 使能UART的RXD功能
        HAL_UART_ENABLE_IT(hUart, UART_IT_SOURCE_RC);
    }
    switch (hUart->RxDoneFun)                                         // 仅异步模式可以使用不定长串口功能
    {
        case UART_RXDONE_FIXLEN:
            hUart->RxDone_Func = UART_RxDoneFunc_FixLen;
            HAL_UART_ENABLE_IT(hUart, UART_IT_SOURCE_RC);
            break;
        case UART_RXDONE_EOP:
            hUart->Instance->RXMATCH = hUart->RxEopChar;
            hUart->Instance->CR2_f.RXMATCHEN = 1;
            hUart->RxDone_Func = UART_RxDoneFunc_RxMatch;
            HAL_UART_ENABLE_IT(hUart, UART_IT_SOURCE_RC | UART_IT_SOURCE_RXMATCH);
            break;
        case UART_RXDONE_IDLE:
            hUart->RxDone_Func = UART_RxDoneFunc_RxIdle;
            HAL_UART_ENABLE_IT(hUart, UART_IT_SOURCE_RC | UART_IT_SOURCE_RXIDLE);
            break;
        default:
            break;
    }
    return HAL_OK;
}


/*******************************************************************************
  * @brief  查询待通过中断接收的数据是否接收完成
  * @param  hUart      : 待通信的UART句柄
  * @retval HAL status : HAL_OK       代表成功完成接收
  *                      HAL_BUSY     代表正在接收
  *                      HAL_ERROR    代表接收出错
  *                      HAL_OVERFLOW 代表接收溢出
  */
HAL_StatusTypeDef HAL_UART_Receive_IT_IsComplete(UART_HandleTypeDef *hUart)
{
    if (hUart == NULL)
    {
        return HAL_ERROR;
    }

    return hUart->RxState;
}


/*******************************************************************************
  * @brief  在中断服务程序中发送并接收UART数据
  * @param  hUart : UART句柄指针，指向包含UART配置、通信参数的结构体
  * @retval None
  * @note   需要在UARTx的中断服务程序中调用 HAL_UART_IRQHandler 函数
  *         在调用前，需使能NVIC
  */
void HAL_UART_IRQHandler(UART_HandleTypeDef *hUart)
{
    uint32_t IsrFlags  = hUart->Instance->ISR;
    hUart->Flags       = IsrFlags & hUart->Instance->IER;             // 获取有效的中断源

    // UART 接收状态是否出错
    if (IsrFlags & UART_IT_FLAG_ERROR)
    {
        // CallBack
        //
        HAL_UART_DISABLE_IT(hUart, UART_IT_SOURCE_RC);
        hUart->RxState = HAL_ERROR;
    }
   
    // UART 运行正常
    if (hUart->RxState == HAL_BUSY)                                   // UART当前正在接收
    {
        if (hUart->Flags & UART_IT_FLAG_RC) 
        {
            hUart->RxISR(hUart);
        }
        hUart->RxDone_Func(hUart);                                    // 任务结束判断
    }

    if (hUart->TxState == HAL_BUSY)                                   // UART当前正在发送
    {
        if (hUart->Flags & UART_IT_FLAG_TXE)                             
        {
            hUart->TxISR(hUart);
            if (hUart->TxXferCount == 0U)
            {
                HAL_UART_DISABLE_IT(hUart, UART_IT_SOURCE_TXE);       // 禁止TXE中断
                HAL_UART_ENABLE_IT(hUart, UART_IT_SOURCE_TC);         // 打开TC中断，等待最后一帧发送完成
            }
        }
        if (hUart->Flags & UART_IT_FLAG_TC)                           // 判断UART是否发送完成
        {
            HAL_UART_CLR_FLAG(hUart, UART_IT_FLAG_TC);
            if (!(hUart->Instance->ISR & UART_IT_FLAG_TXBUSY))
            {
                HAL_UART_DISABLE_IT(hUart, UART_IT_FLAG_TC);
                hUart->TxState = HAL_OK;
            }
        }
    }
}


/*******************************************************************************
  * @brief  通过GTIMx的CAP功能侦测主机发送数据的波特率
  *         并配置UARTx的波特率为侦测到的波特率
  * @param  UARTx: UART名称
  *                @arg SYM_UART1
  *                @arg SYM_UART2
  * @param  GTIMx: GTIM名称
  *                @arg SYM_GTIM1
  * @retval NA
  * @note   在波特率侦测阶段，主机所发送的数据必须为0xF8
  *         需要在主程序中使能GTIMx的工作时钟
  */
void HAL_UART_AutoBaud(UART_TypeDef *UARTx, GTIM_TypeDef *GTIMx)
{
    uint16_t CapSrc;
    uint32_t tmp32;

    switch ((uint32_t)UARTx)
    {
        case (uint32_t)SYM_UART1:  CapSrc = 0x0303; break;
        case (uint32_t)SYM_UART2:  CapSrc = 0x0404; break;
        default                 :  break;
    }

    // 配置GTIMx的CHx来源为UARTx的RXD信号
    switch ((uint32_t)GTIMx)
    {
        case (uint32_t)SYM_GTIM1:  SYM_GTIM1->TISEL = CapSrc;  break;
        default                 :  SYM_GTIM1->TISEL = CapSrc;  break;
    }

    // 配置GTIM工作于输入捕捉模式
    GTIMx->CR1  = 0x00;
    GTIMx->CCMR1CAP = 0x0101;                                         // CC1S TI1/CC2S TI2
    GTIMx->CCER = 0x0013;                                             // ch2捕捉上升沿，CH1捕捉下降沿
    GTIMx->ARR  = 0xFFFF;
    GTIMx->CNT  = 0x00;
    GTIMx->EGR  = 0x01;
    GTIMx->ICR  = 0x00;
    GTIMx->CR1  = 0x01;                                               // 启动定时器

    // 暂停UART的RXEN
    REGBITS_CLR(UARTx->CR1, UARTx_CR1_RXEN_Msk);

    // 等待两次捕捉完成
    while ((GTIMx->ISR & GTIMx_ISR_CC2IF_Msk) == 0x00) { ; }
    tmp32 = GTIMx->CCR2 + 0x10000;
    tmp32 = (tmp32 - GTIMx->CCR1 + 2) & 0xFFFF;
    UARTx->BRRF = tmp32>>2;
    UARTx->BRRI = (tmp32>>2)>>4;

    // 使能UART的RXEN
    REGBITS_SET(UARTx->CR1, UARTx_CR1_RXEN_Msk);
}


/*******************************************************************************
  * @brief  通过波特率检测模式1侦测主机发送数据的波特率
  *         并配置UARTx的波特率为侦测到的波特率
  * @param  UARTx: UART名称
  *                @arg SYM_UART1
  * @retval NA
  * @note   仅UART1支持；
  *         波特率侦测阶段，主机所发送的数据必须为0x80
  */
void HAL_UART_AutoBaud1(UART_TypeDef *UARTx)
{
    uint32_t tmp32 = UARTx->TIMARR;

    // 使能波特率检测模式1
    REGBITS_CLR(UARTx->CR1, UARTx_CR1_RXEN_Msk);

    UARTx->BRRF = 0x00;
    UARTx->BRRI = 0x01;
    UARTx->TIMARR = 0x00FFFFFF - 1;
    UARTx->ICR = ~UART_IT_FLAG_BAUD;
    REGBITS_MODIFY(UARTx->CR2, UARTx_CR2_TIMCR_Msk, UART_TIMCR_AUTOBAUD1);
    REGBITS_SET(UARTx->CR1, UARTx_CR1_RXEN_Msk);

    // 等待波特率检测完成
    while (REGBITS_GET(UARTx->ISR, UART_IT_FLAG_BAUD) == 0) { ; }

    // 清除相应标志并更新波特率
    UARTx->ICR    = ~(UART_IT_FLAG_BAUD | UART_IT_FLAG_RC | UART_IT_FLAG_FE | UART_IT_FLAG_PE);
    UARTx->BRRI   = (UARTx->TIMCNT + 0x04) >> 7;
    UARTx->BRRF   = (UARTx->TIMCNT + 0x04) >> 3;
    UARTx->TIMARR = tmp32;
}


/*******************************************************************************
  * @brief  通过波特率检测模式2侦测主机发送数据的波特率
  *         并配置UARTx的波特率为侦测到的波特率
  * @param  UARTx: UART名称
  *                @arg SYM_UART1
  * @retval NA
  * @note   仅UART1支持
  *         在波特率侦测阶段，主机所发送的数据必须为0x55
  */
void HAL_UART_AutoBaud2(UART_TypeDef *UARTx)
{
    uint32_t tmp32 = UARTx->TIMARR;

    // 使能波特率检测模式2
    REGBITS_CLR(UARTx->CR1, UARTx_CR1_RXEN_Msk);

    UARTx->BRRF   = 0x00;
    UARTx->BRRI   = 0x01;
    UARTx->TIMARR = 0x00FFFFFF - 1;
    UARTx->ICR    = ~UART_IT_FLAG_BAUD;
    REGBITS_MODIFY(UARTx->CR2, UARTx_CR2_TIMCR_Msk, UART_TIMCR_AUTOBAUD2);
    REGBITS_SET(UARTx->CR1, UARTx_CR1_RXEN_Msk);

    // 等待波特率检测完成
    while (REGBITS_GET(UARTx->ISR, UART_IT_FLAG_BAUD) == 0) { ; }

    // 清除相应标志并更新波特率
    UARTx->ICR    = ~(UART_IT_FLAG_BAUD | UART_IT_FLAG_RC | UART_IT_FLAG_FE | UART_IT_FLAG_PE);
    UARTx->BRRI   = (UARTx->TIMCNT + 0x04) >> 7;
    UARTx->BRRF   = (UARTx->TIMCNT + 0x04) >> 3;
    UARTx->TIMARR = tmp32;
}


/*******************************************************************************
  * @brief  LIN 模式使能
  * @param  UARTx       : UART名称
  *                       @arg SYM_UART1
  * @param  RxBreakLen  : LIN模式接收间隔段的长度
  *                       @arg LIN_BRKLEN_10BIT
  *                       @arg LIN_BRKLEN_11BIT
  * @retval None
  * @note   仅UART1支持
  *         需调用HAL_UART_Init / HAL_UART_LpInit 之后，才可调用该函数
  */
void HAL_LIN_Enable(UART_TypeDef *UARTx, LIN_BrkLenTypeDef RxBreakLen)
{
    REGBITS_CLR(UARTx->CR1, UARTx_CR1_SINGLE_Msk);
    REGBITS_MODIFY(UARTx->CR3, UARTx_CR3_LINBRK_Msk, UARTx_CR3_LINEN_Msk | RxBreakLen);
}


/*******************************************************************************
  * @brief  LIN 模式发送间隔段
  * @param  UARTx      : UART名称
  *                      @arg SYM_UART1
  * @param  TxBreakLen : LIN模式接收间隔段的长度, 根据协议SendBreakLen应该大于等于13
  * @retval None
  * @note   仅UART1支持
  *         需调用HAL_LIN_Enable 之后，才可调用该函数
  */
void HAL_LIN_SendBreak(UART_TypeDef *UARTx, uint16_t TxBreakLen)
{
    UARTx->ICR = ~UART_IT_FLAG_TC;
    UARTx->TDR = (TxBreakLen & 0x1FF) | UARTx_TDR_BREAK_Msk;
    while (REGBITS_GET(UARTx->ISR, UARTx_ISR_TC_Msk) == 0x00) { ; }
}


/************************ (C) COPYRIGHT SIYIMicro *****END OF FILE*************/
